/*
  生成器函数在遇到yield之前会正常执行，
  遇到之后会回立即停止，函数作用域状态会保留，
  停止后只能通过调用next()执行
*/

// 此时的yield有点像函数中的中间返回语句，
// 它返回的值会出现在next()的返回对象里，
// 通过它退出的生成器done会处在: false状态。
// return返回的会处在true状态
function *generatorFun() {
  yield 'javascript'
  return 'hello'
}

let generatorObject = generatorFun()

console.log(generatorObject.next()) // {value: undefind, done: false}
console.log(generatorObject.next()) // {value: hello, done: true}

/*
  生成器函数内部会对每个生成器对象区分作用域，
  各个生成器对象调用next()互不影响
*/
function *generatorFun1() {
  yield 'foo'
  yield 'bar'
  return 'baz'
}

let generatorObject1 = generatorFun1()
let generatorObject2 = generatorFun1()

console.log('generatorObject1输出:',generatorObject1.next()) // 输出相等的值
console.log('generatorObject2输出:',generatorObject2.next()) // 输出相等的值 

/*
  yield只能直接在生成器函数中，间接在回报错
*/

/*
  生成器对象作为可迭代对象
*/
function *generatorFun3() {
  yield 1
  yield 2
}

for (val of generatorFun3()) {
  console.log(val) // 1 2
}

// 自定义一个可迭代对象，这个对象会产生一个迭代器，可指定迭代器迭代次数
function *nTimes(n) {
  while(n--) {
    yield;
  }
}
for (let _ of nTimes(3)) {
  console.log('foo') // foo foo foo
}


/*
  使用yield实现输入输出
  yield可以当做函数的中间参数，
  上一次让生成器函数暂停的yield会接受next()函数的第一个数值
  第一次调用next传入的值不会被使用，因为这个是为了开始执行生成器
*/
function *generatorFun4(init) {
  console.log(init)
  console.log(yield)
  console.log(yield)
  console.log(yield)
}
const generatorObject3 = generatorFun4('hello')
generatorObject3.next('bar') // hello 第一次调用的不被使用
generatorObject3.next('baz') // baz
generatorObject3.next('qux') // qux

// yield可以同时用于输入和输出
function *generatorFun5() {
  return yield 'foo'
}

let generatorObject4 = generatorFun5()
//这段代码的执行逻辑:
//因为函数要对整个表达书求值才能确定要返回的值，所以遇到yield关键字的时候会暂停执行并计算出要产生的值'foo',
//下一次调用next()传入了‘bar’，作为交给同一个yield的值。然后这个值被确定出来为本次生成器函数要返回的值
console.log(generatorObject4.next()) // Object { value: "foo", done: false }
console.log(generatorObject4.next('bar')) // Object 

/*
  产生可迭代对象
  可以使用星号增强yield的行为，让他能够迭代一个可迭代的对象，从而一次产出一个值
*/
function *generatorFun5() {
  yield* [1,2,3]
  
  // 上面的代码等价于
  // for (const val of [1,2,3]) {
  //   yield val
  // }
}
let generatorObject5 = generatorFun5()
for(const val of generatorObject5) {
  console.log // 1 2 3
}
